<template>
  <div class="selectOption" :class="{'disabled': disabled}">
    <slot v-if="$slots.default"></slot>
    <div style="width: 100%;position: relative;" v-if="!$slots.default">
      <div class="valueBox pageFlex pageAlignCenter" @click="showModal()" >
        <slot name="formValue" v-if="$slots.formValue"></slot>
        <el-text class="value" line-clamp="1" v-else>{{ formValue || placeHolder }}</el-text>
        <el-icon><ArrowRight /></el-icon>
      </div>
      <div class="bgFF treeBox" v-if="show">
        <el-text class="treeBoxTitle">{{ title }}</el-text>
        <div style="width: 100%;height: 200px;overflow: auto;">
          <el-tree ref="treeRef" show-checkbox lazy :check-strictly="true" :node-key="treeNodeKey" :props="treeProps"
            :load="loadOptions"
            @check="handleCheckChange"/>
        </div>
        <el-row :gutter="10" style="margin-top: 10px;padding: 0 10px;justify-content: flex-end;">
          <el-col :span="1.5">
            <el-button link type="primary" @click="clearChoose()">清空选择</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button link type="primary" @click="confirmChoose()">确认</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button link type="primary" @click="handleCancel">取消</el-button>
          </el-col>
        </el-row>
      </div>
    </div>
  </div>
</template>
<script setup>
/**
 * 自定义树状结构数据选择器
 * 可以自设#default，用于整个替换选择器的布局，可自设选择器布局
 * 也可以自设#formValue,用于选择后的数据显示
 *
 * */
import {nextTick, defineProps, defineEmits, defineExpose, onMounted } from 'vue';
const { proxy } = getCurrentInstance();
const props = defineProps({
  disabled: {
    type: Boolean,
    default: false
  },
  selectType: {
    type: String,
    default: 'one',
  },
  maxSelectLength: {
    type: String,
    default: '',
  },
  placeHolder: {
    type: String,
    default: '请选择'
  },
  title: {
    type: String,
    default: '选择'
  },
  parentId: {
    type: [String, Number],
    default: 0
  },
  modelValue: {
    type: [Array, String, Number],
    default: ''
  },
  defaultFormValue: {
    type: String,
    default: ''
  },
  treeProps: {
    type: Object,
    default: () => {
      return {
        label: 'name',
        disabled: 'checked'
      }
    }
  },
  treeNodeKey: {
    type: String,
    default: 'id'
  },
  treeNodeValue: {
    type: String,
    default: 'name'
  }
});
const emits = defineEmits(['update:modelValue', 'loadOptions', 'chooseError', 'chooseConfirm', 'clearChoose']);
const checkedList = ref([]);
const formValue = ref('');
const show = ref(false);
const selectedValue = ref([]);
const loadApiData = ref([]);
function showModal(){
  if(props.disabled) return;
  show.value = true;
  nextTick(()=>{
    proxy.$refs.treeRef.setCheckedKeys(selectedValue.value);
  })
}
function loadOptions(node, resolve){
  emits('loadOptions', {node, resolve});
}
function handleLoadApi(data, node, resolve){
  if(props.selectType !== 'one' && data.length === 0){
    loadApiData.value.push(node.data[props.treeNodeKey]);
  }
  resolve(data);
}
function handleCheckChange(e){
  proxy.$refs.treeRef.setCheckedKeys([]);
  if(props.selectType === 'one'){
    if(selectedValue.value.length === 0){
      selectedValue.value.push(e[props.treeNodeKey]);
    }else{
      if(e[props.treeNodeKey] === selectedValue.value[0]){
        selectedValue.value = [];
      }else{
        selectedValue.value[0] = e[props.treeNodeKey];
      }
    }
  }else{
    let index1 = selectedValue.value.findIndex(item => item === e[props.treeNodeKey]);
    setNode(e[props.treeNodeKey], []);
    if(index1 !== -1){
      let index2 = selectedValue.value.findIndex(item => item === e[props.treeNodeKey]);
      selectedValue.value.splice(index2, 1);
    }
  }
  proxy.$refs.treeRef.setCheckedKeys(selectedValue.value);
}
function setNode(parentId, arr){
  let resNode = proxy.$refs.treeRef.getNode(parentId);
  if(resNode.parent.key){
    arr.unshift(resNode.data[props.treeNodeKey]);
    setNode(resNode.parent.key, arr);
  }else{
    arr.unshift(parentId);
    selectedValue.value = arr;
  }
}
function clearChoose(){
  selectedValue.value = [];
  proxy.$refs.treeRef.setCheckedKeys([]);
  loadApiData.value = [];
  formValue.value = '';
  hideModal();
  emits('clearChoose');
}
function confirmChoose(){
  let length = selectedValue.value.length;
  if(length === 0){
    emits('chooseError', {code: 1, msg: '未选择任何选项！'});
    return false
  }
  let keys = proxy.$refs.treeRef.getCheckedKeys();
  let values = proxy.$refs.treeRef.getCheckedNodes();
  if(props.selectType === 'one'){
    formValue.value = values[0][props.treeNodeValue];
    hideModal();
    emits('update:modelValue', keys[0]);
    emits('chooseConfirm', {keys, values});
  }else{
    let flag = false;
    if(props.maxSelectLength){
      if(props.maxSelectLength === 'more'){
        flag = true;
      }else{
        flag = keys.length === Number(props.maxSelectLength);
      }
    }else{
      let index1 = loadApiData.value.findIndex(item=>item === selectedValue.value[length - 1]);
      flag = index1 !== -1;
    }
    if(flag){
      values.forEach((item, index) => {
        if(index === 0){
          formValue.value = item[props.treeNodeValue];
        }else{
          formValue.value += '/'+item[props.treeNodeValue];
        }
      });
      hideModal();
      emits('update:modelValue', keys);
      emits('chooseConfirm', {keys, values});
    }else{
      emits('chooseError', {code: 2, msg: '未完整选择'})
    }
  }
}
function handleCancel(){
  hideModal();
  if(props.modelValue){
    if(props.selectType === 'one'){
      checkedList.value = [props.modelValue];
    }else{
      checkedList.value = props.modelValue;
    }
  }
  selectedValue.value = checkedList.value;
}
function hideModal(){
  show.value = false;
}
function setDefaultData(){
  formValue.value = props.defaultFormValue || '';
  if(props.modelValue){
    if(props.selectType === 'one'){
      checkedList.value = [props.modelValue];
    }else{
      checkedList.value = props.modelValue;
    }
  }
  selectedValue.value = checkedList.value;
}
onMounted(()=>{
  setDefaultData();
})
defineExpose({
  formValue,
  handleLoadApi,
  hideModal,
  setDefaultData
})
</script>
<style scoped lang="scss">
@import "@/assets/styles/public.scss";
.selectOption{
  width: 100%;
  .valueBox{
    width: 100%;
    height: 32px;
    background-color: $formBgSet;
    padding: 0 10px;
    color: var(--el-text-color-regular);
    cursor: pointer;
    .value{
      flex: 1;
    }
  }
  .treeBox{
    min-width: 100%;
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 5;
    padding: 0 5px 10px 0px;
    font-size: 12px;
    border-radius: 4px;
    border: 1px solid var(--el-border-color-light);
    box-shadow: 0px 0px 12px rgba(0, 0, 0, .12);
    .treeBoxTitle{
      padding: 10px;
      font-size: 15px;
      font-weight: 600;
    }
  }
  &.disabled{
    .valueBox{
      cursor: not-allowed;
    }
  }
}
</style>